using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;

namespace LiteRP
{
    public class LiteRenderPipeline : RenderPipeline
    {
        private RenderGraph m_RenderGraph; // 渲染图
        private LiteRenderGraphRecorder m_RenderGraphRecorder; // 渲染图录制器
        private  ContextContainer m_ContextContainer; // 上下文容器

        public LiteRenderPipeline(LiteRPAsset asset)
        {
            InitializeRenderGraph();
        }

        protected override void Dispose(bool disposing)
        {
            CleanupRenderGraph();
            base.Dispose(disposing);
        }
        
        // 初始化渲染图
        private void InitializeRenderGraph()
        {
            m_RenderGraph = new RenderGraph("LiteRPRenderGraph");
            m_RenderGraph.nativeRenderPassesEnabled = LiteRPUtils.CanNativeRenderPassEnable();
            if(!m_RenderGraph.nativeRenderPassesEnabled ) Debug.Log("Lite Render Pipeline:  Native render passes disabled");
            
            m_RenderGraphRecorder = new LiteRenderGraphRecorder();
            m_ContextContainer = new ContextContainer();
        }
        
        // 清理渲染图
        private void CleanupRenderGraph()
        {
            m_ContextContainer?.Dispose();
            m_ContextContainer = null;
            
            m_RenderGraphRecorder?.Dispose();
            m_RenderGraphRecorder = null;
            
            m_RenderGraph?.Cleanup();
            m_RenderGraph = null;
        }

        // 老的接口
        protected override void Render(ScriptableRenderContext context, Camera[] cameras)
        {
            // 不需要实现
        }

        // 新的接口
        protected override void Render(ScriptableRenderContext context, List<Camera> cameras)
        {
            // 开始渲染上下文
            BeginContextRendering(context, cameras);

            // 渲染相机
            for (int i = 0; i < cameras.Count; i++)
            {
                var camera = cameras[i];
                // 渲染相机
                RenderCamera(context, camera);
            }
            
            // 结束渲染图
            m_RenderGraph.EndFrame();

            // 结束渲染上下文
            EndContextRendering(context, cameras);
        }

        private void RenderCamera(ScriptableRenderContext context, Camera camera)
        {
            // 开始渲染相机
            BeginCameraRendering(context, camera);

            // 准备FrameData
            if (PrepareFrameData(context, camera))
            {
                // 为相机创建CommandBuffer
                CommandBuffer cmd = CommandBufferPool.Get();
          
                // 录制并执行渲染图
                RecordAndExecuteRenderGraph(context, camera, cmd);
            
                // 提交命令缓冲区
                context.ExecuteCommandBuffer(cmd);
                // 释放命令缓冲区
                cmd.Clear();
                CommandBufferPool.Release(cmd);
                // 提交渲染上下文
                context.Submit();
                
            }

            // 结束渲染相机
            EndCameraRendering(context, camera);
        }
        
        // 准备FrameData
        private bool PrepareFrameData(ScriptableRenderContext context, Camera camera)
        {
            // 获取摄像机剔除参数，并进行剔除
            ScriptableCullingParameters cullingParams;
            if (!camera.TryGetCullingParameters(out cullingParams))
            {
                return  false;
            }
            CullingResults cullingResults = context.Cull(ref cullingParams);

            CameraData cameraData = m_ContextContainer.GetOrCreate<CameraData>();
            cameraData.camera = camera;
            cameraData.cullingResults = cullingResults;

            return true;
        }

        // 录制并执行渲染图
        private void RecordAndExecuteRenderGraph(ScriptableRenderContext context, Camera camera, CommandBuffer cmd)
        {
            RenderGraphParameters renderGraphParams = new RenderGraphParameters()
            {
                executionName = camera.name,
                commandBuffer =  cmd,
                scriptableRenderContext = context,
                currentFrameIndex = Time.frameCount
            };
            
            m_RenderGraph.BeginRecording(renderGraphParams);
            
            // 开启记录时间线
            m_RenderGraphRecorder.RecordRenderGraph(m_RenderGraph, m_ContextContainer);
            
            m_RenderGraph.EndRecordingAndExecute();
        }

        private void RenderCameraObjectList(ScriptableRenderContext context, Camera camera,  CommandBuffer cmd, CullingResults cullingResults )
        {
            bool clearColor = camera.clearFlags == CameraClearFlags.Color;
            bool clearDepth = camera.clearFlags != CameraClearFlags.Nothing;
            bool clearSkybox = camera.clearFlags == CameraClearFlags.Skybox;
            
            // 清理渲染目标
            cmd.ClearRenderTarget(clearDepth, clearColor, CoreUtils.ConvertSRGBToActiveColorSpace(camera.backgroundColor) );
            
            // 指定渲染排序设置SortSettings
            var sortSettings = new SortingSettings(camera);
            // 指定渲染状态设置DrawingSettings
            var drawingSettings = new DrawingSettings(LiteRenderGraphRecorder.ShaderTagId, sortSettings);
            
            
            // 绘制不透明物体
            sortSettings.criteria = SortingCriteria.CommonOpaque;
            // 指定渲染过滤设置FilterSettings
            var filterSettings = new FilteringSettings(RenderQueueRange.opaque);
            // 创建渲染队列
            var rendererListParams = new RendererListParams(cullingResults, drawingSettings, filterSettings);
            var rendererList = context.CreateRendererList(ref rendererListParams);
            // 绘制渲染队列
            cmd.DrawRendererList(rendererList);
            
            // 渲绘制天空盒
            if (clearSkybox)
            {
                var skyboxRendererList = context.CreateSkyboxRendererList(camera);
                cmd.DrawRendererList(skyboxRendererList);
            }

            
            // 绘制透明物体
            sortSettings.criteria = SortingCriteria.CommonTransparent;
            // 指定渲染过滤设置FilterSettings
            filterSettings = new FilteringSettings(RenderQueueRange.transparent);
            // 创建渲染队列
            rendererListParams = new RendererListParams(cullingResults, drawingSettings, filterSettings);
            rendererList = context.CreateRendererList(ref rendererListParams);
            // 绘制渲染队列
            cmd.DrawRendererList(rendererList);
        }
    }
}